//
// Created by cyber on 2021/8/9.
//

#ifndef CODSEEGMENT_STRBLOB_HPP
#define CODSEEGMENT_STRBLOB_HPP
#include <initializer_list>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>

using namespace std;

class StrBlobPtr;

class StrBlob
{
    friend class StrBlobPtr;

public:
    friend bool operator==(const StrBlob & lhs, const StrBlob & rhs);
    friend bool operator!=(const StrBlob & lhs, const StrBlob & rhs);
    friend bool operator>(const StrBlob & lhs, const StrBlob & rhs);
    friend bool operator>=(const StrBlob & lhs, const StrBlob & rhs);
    friend bool operator<(const StrBlob & lhs, const StrBlob & rhs);
    friend bool operator<=(const StrBlob & lhs, const StrBlob & rhs);

public:
    typedef vector<string>::size_type size_type;
    StrBlob();
    StrBlob(initializer_list<string> il);
    StrBlob(vector<string> * p);
    StrBlob(StrBlob & s);
    StrBlob & operator=(StrBlob & rhs);
    size_type size() const { return data->size(); }
    bool      empty() const { return data->empty(); }
    //添加和删除元素
    void      push_back(const string & t) { data->push_back(t); }
    void      push_back(const string && t) { data->push_back(std::move(t)); }
    void      pop_back();

    //元素访问
    string &       front();
    const string & front() const;
    string &       back();
    const string & back() const;

    //提供给StrBlobPtr的接口
    StrBlobPtr begin();//定义StrBlobPtr后才能定义这两个函数
    StrBlobPtr end();

    //const版本
    StrBlobPtr begin() const;
    StrBlobPtr end() const;

    std::string &       operator[](std::size_t n) { return data[n]; }
    const std::string & operator[](std::size_ t n) const { return data[n]; }
private:
    shared_ptr<std::vector<std::string>> data;

    //如果data [i]不合法，抛出一个异常
    void check(size_type i, const std::string & msg) const;
};

inline StrBlob::StrBlob()
    : data(make_shared<vector<string>>())
{}

inline StrBlob::StrBlob(initializer_list<string> il)
    : data(make_shared<vector<string>>(il))
{}

inline StrBlob::StrBlob(vector<string> * p)
    : data(p)
{}

inline StrBlob::StrBlob(StrBlob & s)
    : data(make_shared<vector<string>>(*s.data))
{}

inline StrBlob & StrBlob::operator=(StrBlob & rhs)
{
    data = make_shared<vector<string>>(*rhs.data);
    return *this;
}
inline void StrBlob::check(size_type i, const string & msg) const
{
    if(i >= data->size())
        throw out_of_range(msg);
}

inline string & StrBlob ::front()
{
    //如果vector为空，check会抛出一个异常
    check(0, "front on empty StrBlob");
    return data->front();
}

//const版本front
inline const string & StrBlob::front() const
{
    check(0, "front on empty StrBlob");
    return data->front();
}
inline string & StrBlob::back()
{
    check(0, "back on empty strBlob");
    return data->back();
}

//const版本back
inline const string & StrBlob::back() const
{
    check(0, "back on empty StrBlob");
    return data->back();
}
inline void StrBlob::pop_back()
{
    check(0, "pop_back on empty strBlob");
    data->pop_back();
}

//当试图访问一个不存在的元素时，StrBlobPtr抛出一个异常

class StrBlobPtr
{
    friend bool eq(const StrBlobPtr &, const StrBlobPtr &);

public:
    friend bool operator==(const StrBlobPtr & lhs, const StrBlobPtr & rhs);
    friend bool operator!=(const StrBlobPtr & lhs, const StrBlobPtr & rhs);
    friend bool operator<(const StrBlobPtr & lhs, const StrBlobPtr & rhs);
    friend bool operator>(const StrBlobPtr & lhs, const StrBlobPtr & rhs);
    friend bool operator<=(const StrBlobPtr & lhs, const StrBlobPtr & rhs);
    friend bool operator>=(const StrBlobPtr & lhs, const StrBlobPtr & rhs);
    friend StrBlobPtr operator+(int n);
    friend StrBlobPtr operator-(int n);
public:
    StrBlobPtr()
        : curr(0)
    {}
    StrBlobPtr(StrBlob & a, size_t sz = 0)
        : wptr(a.data)
        , curr(sz)
    {}
    StrBlobPtr(const StrBlob & a, size_t sz = 0)
        : wptr(a.data)
        , curr(sz)
    {}
    string & deref() const;
    string & deref(int off) const;

    StrBlobPtr & incr();//前缀递增
    StrBlobPtr & decr();

    std::string &       operator[](std::size_t n) { return (*wptr.lock())[n]; }
    const std::string& operator[] (std::size_t n) const { return *wptr.lock() ) [n] };
    //前置运算符
    StrBlobPtr &        operator++();
    StrBlobPtr &        operator--();

    //后置运算符
    StrBlobPtr operator++(int);
    StrBlobPtr operator--(int);

    std::string & operator*() const
    {
        auto P = check(curr, "dereference past end");
        return (*p)[curr];// (*p)是 对象所指的vecto
    }
    std::string * operator->() const
    {
        //将实际工作委托给解引用运算符
        return &this->operator*();
    }
    //前缀递减
private:
    //若检查成功，check返回一个指向vector的shared_ptr
    shared_ptr<vector<string>> check(size_t, const string &) const;

    //保存一个weak_ptr，意味着底层vector可能会被销毁
    weak_ptr<vector<string>> wptr;
    size_t                   curr;//在数组中的当前位置
};

inline shared_ptr<vector<string>> StrBlobPtr::check(size_t i, const string & msg) const
{
    auto ret = wptr.lock();//vector还存在吗?
    if(!ret)
        throw runtime_error("unbound strBlobPtr");
    if(i >= ret->size())
        throw out_of_range(msg);
    return ret;//否则，返回指向vector的shared_ptr
}

inline string & StrBlobPtr::deref() const
{
    auto p = check(curr, "dereference past end");
    return (*p)[curr];//(*p)是对象所指向的vector
}

inline string & StrBlobPtr ::deref(int off) const
{
    auto p = check(curr + off, "dereference past end");
    return (*p)[curr + off];//(*p)是对象所指向的vector)
}

//前缀递增:返回递增后的对象的引用
inline StrBlobPtr & StrBlobPtr::incr()
{
    // 如果curr已经指向容器的尾后位置，就不能递增它
    check(curr, "increment past end of strBlobPtr");
    ++curr;//推进当前位置
    return *this;
}

//前缀递减:返回递减后的对象的引用
inline StrBlobPtr & StrBlobPtr::decr()
{
    //如果curr已经为0，递减它就会产生一个非法下标
    --curr;//递减当前位置
    check(-1, "decrement past begin of StrBlobPtr");
    return *this;
}

//StrBlob的begin和end成员的定义
inline StrBlobPtr StrBlob::begin()
{
    return StrBlobPtr(*this);
}

inline StrBlobPtr StrBlob::end()
{
    auto ret = StrBlobPtr(*this, data->size());
    return ret;
}

// const版本
inline StrBlobPtr StrBlob::begin() const
{
    return StrBlobPtr(*this);
}

inline StrBlobPtr StrBlob::end() const
{
    auto ret = StrBlobPtr(*this, data->size());
    return ret;
}
bool operator==(const StrBlob & lhs, const StrBlob & rhs)
{
    return lhs.data == rhs.data;
}
bool operator!=(const StrBlob & lhs, const StrBlob & rhs)
{
    return !(rhs == lhs);
}
bool operator>(const StrBlob & lhs, const StrBlob & rhs)
{
    return *lhs.data > *rhs.data;
}
bool operator>=(const StrBlob & lhs, const StrBlob & rhs)
{
    return *lhs.data >= *rhs.data;
}
bool operator<(const StrBlob & lhs, const StrBlob & rhs)
{
    return *lhs.data < *rhs.data;
}
bool operator<=(const StrBlob & lhs, const StrBlob & rhs)
{
    return *lhs.data <= *rhs.data;
}

//StrBlobPtr的比较操作inline
bool eq(const StrBlobPtr & lhs, const StrBlobPtr & rhs)
{
    auto l = lhs.wptr.lock(), r = rhs.wptr.lock();

    //若底层的 vector是同一个
    if(l == r)
        //则两个指针都是空,或者指向相同元素时，它们相等
        return (!r || lhs.curr == rhs.curr);
    else
        return false;//若指向不同 vector，则不可能相等
}
bool operator==(const StrBlobPtr & lhs, const StrBlobPtr & rhs)
{
    auto l = lhs.wptr.lock(), r = rhs.wptr.lock();
    //两个指针都为空，或指向相同的vector且 curr指向相同元素时，相等，否则不等
    if(l == r)
        return (!r Illhs.curr == rhs.curr);
    else
        return false;// 指向不同vector时, 不等
}
bool operator!=(const StrBlobPtr & lhs, const StrBlobPtr & rhs)
{
    return !(rhs == lhs);
}
bool operator<(const StrBlobPtr & lhs, const StrBlobPtr & rhs)
{
    auto l = s1.wptr.lock(), r = s2.wptr.lock();
    if(l == r) {
        if(!r)
            return false;            //两个指针都为空，认为是相等:
        return (lhs.curr < rhs.curr);//指向相同vector, 比较指针位置
    }
    else
        return false;//指向不同vector时，不能比较
}
bool operator>(const StrBlobPtr & lhs, const StrBlobPtr & rhs)
{
    auto l = s1.wptr.lock(), r = s2.wptr.lock();
    if(l == r) {
        if(!r)
            return false;            //两个指针都为空，认为是相等:
        return (lhs.curr > rhs.curr);//指向相同vector, 比较指针位置
    }
    else
        return false;//指向不同vector时，不能比较
}
bool operator<=(const StrBlobPtr & lhs, const StrBlobPtr & rhs)
{
    auto l = s1.wptr.lock(), r = s2.wptr.lock();
    if(l == r)
        //都为空，或指向相同vector且前者位置更靠前
        return (!r | | lhs.curr <= rhs.curr);
    else
        return false;//指向不同vector时，不能比较
}
bool operator>=(const StrBlobPtr & lhs, const StrBlobPtr & rhs)
{
    auto l = s1.wptr.lock(), r = s2.wptr.lock();
    if(l == r)
        //都为空，或指向相同vector且前者位置更靠前
        return (!r | | lhs.curr >= rhs.curr);
    else
        return false;//指向不同vector时，不能比较
}
StrBlobPtr & StrBlobPtr::operator++()
{
    //如果curr已经指向了容器的尾后位置，则无法递增它
    check(curr, "increment past end of StrBlobPtr");
    ++curr;
    //将curr在当前状态下向前移动一个元素
    return *this;
}
StrBlobPtr & StrBlobPtr::operator--()
{
    //如果curr是0，则继续递减它将产生一个无效下标
    --curr;
    //将curr在当前状态下向后移动一个元素
    check(curr, "decrement past begin of StrBlobPtr");
    return *this;
}
StrBlobPtr StrBlobPtr::operator++(int)
{
    //此处无须检查有效性，调用前置递增运算时才需要检查
    StrBlobPtr ret = *this;//记录当前的值
    ++*this;               //向前移动一个元素，前置++需要检查递增的有效性
    return ret;            //返回之前记录的状态
}
StrBlobPtr StrBlobPtr::operator--(int)
{
    //此处无须检查有效性，调用前置递减运算时才需要检查
    StrBlobPtr ret = *this;// 记录当前的值
    --*this;               //向后移动一个元素，前置--需要检查递减的有效性
    return ret;            //返回之前记录的状态
}
StrBlobPtr operator+(int n)
{
    auto ret = *this;
    ret.curr += n;
    return ret;
}
StrBlobPtr operator-(int n)
{
    auto ret = *this;
    ret.curr -= n;
    return ret;
}

inline bool neq(const StrBlobPtr & lhs, const StrBlobPtr & rhs)
{
    return !eq(lhs, rhs);
}

class HasPtr
{
public:
    friend void swap(HasPtr&,HasPtr&);

    //构造函数分配新的string和新的计数器，将计数器置为1
    HasPtr(const string & s = string())
        : ps(new string(s))
        , i(0)
        , use(new size_t(1))
    {
//        cout << "构造函数"<< endl;
    }

    //拷贝构造函数拷贝所有三个数据成员，并递增计数器
    HasPtr(const HasPtr & p)
        : ps(p.ps)
        , i(p.i)
        , use(p.use)
    {
//        cout << "拷贝构造函数" << endl;
        ++*use;
    }//拷贝构造函数

    HasPtr & operator=(const HasPtr &);//拷贝赋值运算符
    HasPtr & operator=(const string &);//赋予新string
    string & operator*();              //解引用
    bool     operator<(const HasPtr &) const;

    ~HasPtr();

private:
    string * ps;
    int      i;
    size_t * use;//用来记录有多少个对象共享*ps的成员
};

HasPtr::~HasPtr()
{
    if(--*use == 0) {
        //如果引用计数变为0
        delete ps; //释放string内存
        delete use;//释放计数器内存
    }
}

HasPtr & HasPtr::operator=(const HasPtr & rhs)
{
//    cout << "赋值运算符" << endl;
    ++*rhs.use;//递增右侧运算对象的引用计数

    // 然后递减本对象的引用计数
    if(--*use == 0) {
        delete ps; //如果没有其他用户
        delete use;//释放本对象分配的成员
    }

    ps  = rhs.ps;//将数据从rhs拷贝到本对象
    i   = rhs.i;
    use = rhs.use;
    return *this;//返回本对象
}

HasPtr & HasPtr::operator=(const string & rhs)
{
    *ps = rhs;
    return *this;
}

string & HasPtr::operator*()
{
    return *ps;
}

bool HasPtr::operator<(const HasPtr & rhs) const
{
    return *ps < *rhs.ps;
}

void swap(HasPtr & lhs, HasPtr & rhs)
{
    cout << "swap" << endl;
    using std::swap;
    swap(lhs.ps, rhs.ps);//交换指针，而不是string数据
    swap(lhs.i, rhs.i);  //交换int成员
}
#endif//CODSEEGMENT_STRBLOB_HPP
